const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  status = PENDING;
  value = undefined;
  reason = undefined;
  #onFulfilledCallbacks = [];
  #onRejectedCallbacks = [];
  constructor(executor) {
    const resolve = value => {
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
        this.#onFulfilledCallbacks.forEach(callback => callback(this.value));
      }
    };
    const reject = reason => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        this.#onRejectedCallbacks.forEach(callback => callback(this.reason));
      }
    };
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  then(onFulfilled, onRejected) {
    const _onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    const _onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : reason => {
            throw reason;
          };
    const p2 = new MyPromise((resolve, reject) => {
      const handleResolve = () => {
        try {
          const x = _onFulfilled(this.value);
          resolvePromise(p2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      };
      const handleReject = () => {
        try {
          const x = _onRejected(this.reason);
          resolvePromise(p2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      };
      if (this.status === FULFILLED) {
        runAsyncTask(() => {
          handleResolve();
        });
      } else if (this.status === REJECTED) {
        runAsyncTask(() => {
          handleReject();
        });
      } else if (this.status === PENDING) {
        this.#onFulfilledCallbacks.push(() => {
          runAsyncTask(() => {
            handleResolve();
          });
        });
        this.#onRejectedCallbacks.push(() => {
          runAsyncTask(() => {
            handleReject();
          });
        });
      }
    });
    return p2;
  }
  catch(onRejected) {
    return this.then(null, onRejected);
  }
  finally(onFinally) {
    // return this.then(onFinally, onFinally); // 这个不太严谨
    return this.then(
      value => MyPromise.resolve(onFinally?.()).then(() => value),
      reason =>
        MyPromise.resolve(onFinally?.()).then(() => {
          throw reason;
        })
    );
  }

  // 如果是Promise实例，直接返回；否则返回一个新的Promise实例
  static resolve(value) {
    if (value instanceof MyPromise) {
      return value;
    }
    return new MyPromise(resolve => {
      // resolve(value);
      resolvePromise(null, value, resolve, () => {});
    });
  }
  // 返回一个失败的Promise实例
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
  // 处理多个Promise实例，返回一个新的Promise实例
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Arugument is not iterable'));
      }
      promises.forEach(promise => {
        MyPromise.resolve(promise).then(
          value => {
            resolve(value);
          },
          error => {
            reject(error);
          }
        );
      });
    });
  }

  /***
   * 处理多个Promise实例，返回一个新的Promise实例,执行所有的Promise实例，记录每个的状态和内容
   * 1.返回一个新的Promise实例
   * 2.不是数组rejct错误信息
   * 3.空数组直接兑现
   * 4.遍历promises数组：记录结果：索引记录顺序、记录全部兑现：根据兑现次数是否等于数组长度；
   * 5.有失败直接reject
   */
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Arugument is not iterable'));
      }
      if (promises.length === 0) {
        resolve(promises);
      }
      const result = [];
      let count = 0;
      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            result[index] = value;
            count++;
            if (count === promises.length) {
              resolve(result);
            }
          },
          error => {
            reject(error);
          }
        );
      });
    });
  }
  // 处理多个Promise实例，返回一个新的Promise实例，
  // 当所有的Promise实例都成功时才成功; 只要有一个失败，就失败
  // 1.返回一个新的Promise实例
  // 2.不是数组rejct错误信息
  // 3.空数组直接兑现
  // 4.遍历promises数组：记录结果：索引记录顺序、记录全部兑现：根据兑现次数是否等于数组长度；
  // 5.成功失败都是reslove
  static allSettled(promises) {
    return new MyPromise((resolve, reject) => {
      const result = [];
      let count = 0;
      promises.forEach(promise => {
        promise.then(
          value => {
            result[index] = {
              status: FULFILLED,
              value
            };
            count++;
            if (count === promises.length) {
              resolve(result);
            }
          },
          error => {
            result[index] = {
              status: REJECTED,
              reason: error
            };
            count++;
            if (count === promises.length) {
              resolve(result);
            }
          }
        );
      });
    });
  }
  static any(promises) {
    return new MyPromise((resolve, reject) => {});
  }
}

const runAsyncTask = callback => {
  setTimeout(callback, 0);
};
// 处理 then 方法的返回值
const resolvePromise = (promise2, x, resolve, reject) => {
  if (x === promise2) {
    throw new TypeError('Chaining cycle detected for promise #<Promise>');
  }
  if (x instanceof MyPromise) {
    // 如果 result 是 MyPromise 实例，等待其状态确定
    x.then(value => resolvePromise(promise2, value, resolve, reject), reject);
  } else {
    resolve(x);
    // 还得处理一些其他情况...
  }
};
const p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    console.log(111);
  }, 1000);
});
p.then(
  res => {},
  err => {}
);

Promise.resolve(p).then();
Promise.reject(p).then();
Promise.all();
Promise.race();
Promise.allSettled();
Promise.any();

const array = [
  { name: '张三', age: 18, group: 'A' },
  { name: '李四', age: 19, group: 'A' },
  { name: '王五', age: 20, group: 'B' },
  { name: '赵六', age: 21, group: 'B' },
  { name: '田七', age: 22, group: 'C' },
  { name: '王八', age: 23, group: 'C' },
  { name: 'xx', age: 18 }
];
const obj = {
  A: [
    { name: '张三', age: 18, group: 'A' },
    { name: '李四', age: 19, group: 'A' }
  ],
  B: [
    { name: '王五', age: 20, group: 'B' },
    { name: '赵六', age: 21, group: 'B' }
  ],
  C: [
    { name: '田七', age: 22, group: 'C' },
    { name: '王八', age: 23, group: 'C' }
  ],
  unknow: [{ name: 'xx', age: 18 }]
};

function transformArr(arr) {
  if (!Array.isArray(arr)) {
    return arr;
  }
  const obj = {};
  arr.forEach(item => {
    const group = item.group || 'unknow';
    if (!obj[group]) {
      obj[group] = [];
    }
    obj[group].push(item);
  });
  return obj;
}
